home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / ODF / OS / FWGraphx / SLRender.cpp < prev    next >
Encoding:
Text File  |  1996-12-16  |  49.3 KB  |  1,892 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLRender.cpp
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWOS.hpp"
  11.  
  12. #ifndef SLRENDER_H
  13. #include "SLRender.h"
  14. #endif
  15.  
  16. #ifndef PRGDEV_H
  17. #include "PRGDev.h"
  18. #endif
  19.  
  20. #ifndef PRTXTBUF_H
  21. #include "PRTxtBuf.h"
  22. #endif
  23.  
  24. #ifndef SLGC_H
  25. #include "SLGC.h"
  26. #endif
  27.  
  28. #ifndef FWRECT_H
  29. #include "FWRect.h"
  30. #endif
  31.  
  32. #ifndef PRMDASH_H
  33. #include "PRMDash.h"
  34. #endif
  35.  
  36. #ifndef FWODGEOM_H
  37. #include "FWODGeom.h"
  38. #endif
  39.  
  40. #ifndef FWSTYLE_H
  41. #include "FWStyle.h"
  42. #endif
  43.  
  44. #ifndef PRPOLY_H
  45. #include "PRPoly.h"
  46. #endif
  47.  
  48. #ifndef SLGRGLOB_H
  49. #include "SLGrGlob.h"
  50. #endif
  51.  
  52. #ifndef PRPICTUR_H
  53. #include "PRPictur.h"
  54. #endif
  55.  
  56. #ifndef PRBITMAP_H
  57. #include "PRBitmap.h"
  58. #endif
  59.  
  60. #ifndef FWGRUTIL_H
  61. #include "FWGrUtil.h"
  62. #endif
  63.  
  64. #ifndef PRGRUTIL_H
  65. #include "PRGrUtil.h"
  66. #endif
  67.  
  68. #ifndef PRICON_H
  69. #include "PRIcon.h"
  70. #endif
  71.  
  72. #ifndef FWMEMMGR_H
  73. #include "FWMemMgr.h"
  74. #endif
  75.  
  76. #if defined(FW_BUILD_MAC) && !defined(__ICONS__)
  77. #include <Icons.h>
  78. #endif
  79.  
  80. #ifndef SLREGION_H
  81. #include "SLRegion.h"
  82. #endif
  83.  
  84. #ifdef FW_BUILD_MAC
  85. #pragma segment FWGraphx_Render
  86. #endif
  87.  
  88. //========================================================================================
  89. // Local helpers
  90. //========================================================================================
  91.  
  92. // All static method can fail
  93. static FW_PlatformCoordinate    PrivTextBox(Environment* ev,
  94.                                     FW_CPrivGraphicsDevice* device,
  95.                                     FW_CPrivTextBuffer *textBuffer, 
  96.                                     const FW_CPlatformRect& box,
  97.                                     FW_TextBoxOptions options,
  98.                                     FW_Boolean draw,
  99.                                     FW_HFont font);
  100.  
  101. static void                        PrivRenderTextBuffer(Environment* ev,
  102.                                     FW_SGraphicContext& gc,
  103.                                     FW_CPrivTextBuffer* textBuffer,
  104.                                     const FW_SPoint& position,
  105.                                     FW_TextAlignment textAlignment,
  106.                                     FW_ERenderVerbs renderVerb,
  107.                                     FW_HInk ink,
  108.                                     FW_HFont font);
  109.                                     
  110. static FW_Fixed                    PrivRenderTextBoxBuffer(Environment* ev,
  111.                                     FW_SGraphicContext& gc,
  112.                                     FW_CPrivTextBuffer* textBuffer, 
  113.                                     const FW_SRect& box,
  114.                                     FW_TextBoxOptions options,
  115.                                     FW_ERenderVerbs renderVerb,
  116.                                     FW_HInk ink,
  117.                                     FW_HFont font);
  118.  
  119. static void                        PrivTextBoxSizeBuffer(Environment* ev,
  120.                                     FW_SGraphicContext& gc,
  121.                                     FW_CPrivTextBuffer *textBuffer, 
  122.                                     FW_HFont font,
  123.                                     FW_TextBoxOptions options,
  124.                                     FW_SRect& textBox);
  125.                         
  126. static void                        PrivTextExtentBuffer(Environment* ev,
  127.                                     FW_SGraphicContext& gc,
  128.                                     FW_CPrivTextBuffer* textBuffer,
  129.                                     FW_HFont font, 
  130.                                     FW_SPoint& textExtent);
  131.  
  132. #ifdef FW_BUILD_MAC
  133.  
  134. static void                        MacSelectInkAndStyle(
  135.                                     FW_CPrivGraphicsDevice* device,
  136.                                     FW_EPrivShapeCategories shapeCategory,
  137.                                     FW_ERenderVerbs renderVerb,
  138.                                     FW_HInk ink,
  139.                                     FW_HStyle style,
  140.                                     FW_Boolean& styleIsDash,
  141.                                     FW_Boolean& styleIsHairline);
  142.  
  143. static FW_CPlatformPoint        MacCalcTextPosition(
  144.                                     FW_CPrivGraphicsDevice* device,
  145.                                     short byteCount, const char* text,
  146.                                     FW_TextAlignment textAlignment,
  147.                                     const FW_CPlatformPoint& position);
  148.  
  149. static void                        MacStrikeOut(
  150.                                     FW_CPrivGraphicsDevice* device,
  151.                                     short beforePosX,
  152.                                     short beforePosY);
  153.  
  154. //----------------------------------------------------------------------------------------
  155. //    FW_PrivSelectHairline -- a Mac utility class for using the SetLineWidth picComment
  156. //----------------------------------------------------------------------------------------
  157.  
  158. class FW_PrivSelectHairline
  159. {
  160. public:
  161.     FW_DECLARE_AUTO(FW_PrivSelectHairline)
  162.         
  163.     FW_PrivSelectHairline(FW_Boolean setHairline);
  164.     ~FW_PrivSelectHairline();
  165.  
  166. private:
  167.  
  168.     enum { eSetLineWidthPicComment = 182 };
  169.  
  170.     FW_PlatformHandle    fData;
  171. };
  172.  
  173. #endif
  174.  
  175. //========================================================================================
  176. // Local macros to make rendering code more straightforward
  177. //========================================================================================
  178.  
  179. #ifdef FW_BUILD_WIN
  180.  
  181. #define FW_CHECK_RENDER    \
  182.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev));
  183.     
  184. #endif
  185.  
  186. #ifdef FW_BUILD_MAC
  187.  
  188. #define FW_CHECK_RENDER    \
  189.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev)); \
  190.     FW_ASSERT(gc.fGraphicDevice->GetPlatformCanvas() == FW_QDGlobals.thePort);
  191.     
  192. #endif
  193.  
  194. #define FW_CHECK_RENDER_VERB \
  195.     if (renderVerb == FW_kNoRendering) \
  196.         return;
  197.  
  198. #define FW_RENDER_PROLOG \
  199.     FW_CHECK_RENDER \
  200.     FW_CPrivGraphicsDevice* device = gc.fGraphicDevice;
  201.  
  202. #define FW_CHECK_INK \
  203.     FW_ASSERT(ink != NULL);
  204.     
  205. #define FW_CHECK_STYLE \
  206.     FW_ASSERT(style != NULL);
  207.     
  208. #define FW_CHECK_FONT \
  209.     FW_ASSERT(font != NULL);
  210.  
  211. //========================================================================================
  212. // Rendering APIs
  213. //========================================================================================
  214.  
  215. //----------------------------------------------------------------------------------------
  216. //    FW_PrivRenderRect
  217. //----------------------------------------------------------------------------------------
  218.  
  219. void SL_API FW_PrivRenderRect(Environment* ev,
  220.                             FW_SGraphicContext&     gc,
  221.                             const FW_SRect&         rect,
  222.                             FW_ERenderVerbs         renderVerb,
  223.                             FW_HInk                 ink,
  224.                             FW_HStyle                 style)
  225. {
  226.     FW_RENDER_PROLOG
  227.     FW_CHECK_RENDER_VERB
  228.     FW_CHECK_INK
  229.     FW_CHECK_STYLE
  230.  
  231.     FW_SOM_TRY
  232.     {
  233.         FW_CPlatformRect plfmRect;
  234.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  235.         FW_FailOnEvError(ev);
  236.             
  237.     #ifdef FW_BUILD_WIN
  238.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, 
  239.                                                         FW_kGeometricShapeWithInvert, 
  240.                                                         renderVerb);
  241.     
  242.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  243.         if (frameBrush)
  244.         {
  245.             int penSizeX = device->fPenSize.x;
  246.             int penSizeY = device->fPenSize.y;
  247.     
  248.             device->fGDIBrush.SelectObject(hDC);
  249.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  250.             ::PatBlt(hDC, plfmRect.right - penSizeX, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  251.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  252.             ::PatBlt(hDC, plfmRect.left, plfmRect.bottom - penSizeY, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  253.         }
  254.         else
  255.         {
  256.             if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite || ink->GetTransferMode() == FW_kSystemHilite)
  257.             {
  258.                 ::InvertRect(hDC, &plfmRect);
  259.             }
  260.             else
  261.             {
  262.                 if (renderVerb == FW_kFill)
  263.                 {
  264.                     plfmRect.right++;
  265.                     plfmRect.bottom++;
  266.                 }
  267.                     
  268.                 ::Rectangle(hDC, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  269.             }
  270.         }
  271.     #endif
  272.     #ifdef FW_BUILD_MAC
  273.         FW_Boolean styleIsDash;
  274.         FW_Boolean styleIsHairline;
  275.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  276.     
  277.         if (renderVerb == FW_kFrame)
  278.         {
  279.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  280.             
  281.             if (styleIsDash)
  282.             {
  283.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  284.     
  285.                 ::MoveTo(plfmRect.left, plfmRect.top);
  286.                 draw.LineTo(plfmRect.right - 1, plfmRect.top);
  287.                 draw.LineTo(plfmRect.right - 1, plfmRect.bottom - 1);
  288.                 draw.LineTo(plfmRect.left, plfmRect.bottom - 1);
  289.                 draw.LineTo(plfmRect.left, plfmRect.top);
  290.             }
  291.             else
  292.             {
  293.                 ::FrameRect(&plfmRect);
  294.             }
  295.         }
  296.         else
  297.         {
  298.             switch (ink->GetTransferMode())
  299.             {
  300.                 case FW_kErase:
  301.                     ::EraseRect(&plfmRect);
  302.                     break;
  303.     
  304.                 case FW_kInvert:
  305.                     ::InvertRect(&plfmRect);
  306.                     break;
  307.                     
  308.                 default:
  309.                     ::PaintRect(&plfmRect);            
  310.             }
  311.         }
  312.     #endif
  313.     }
  314.     FW_SOM_CATCH
  315. }
  316.  
  317. //----------------------------------------------------------------------------------------
  318. //    FW_PrivRenderOval
  319. //----------------------------------------------------------------------------------------
  320.  
  321. void SL_API    FW_PrivRenderOval(Environment* ev,
  322.                             FW_SGraphicContext&     gc,
  323.                             const FW_SRect&         rect,
  324.                             FW_ERenderVerbs         renderVerb,
  325.                             FW_HInk                 ink,
  326.                             FW_HStyle                 style)
  327. {
  328.     FW_RENDER_PROLOG
  329.     FW_CHECK_RENDER_VERB
  330.     FW_CHECK_INK
  331.     FW_CHECK_STYLE
  332.  
  333.     FW_SOM_TRY
  334.     {
  335.         FW_CPlatformRect plfmRect;
  336.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  337.         FW_FailOnEvError(ev);
  338.             
  339.     #ifdef FW_BUILD_WIN
  340.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  341.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  342.     
  343.         if (frameBrush)
  344.         {
  345.             HRGN hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, plfmRect.right + 1, plfmRect.bottom + 1);
  346.             ::FrameRgn(hDC, hrgn, device->fGDIBrush.GetBrush(hDC), device->fPenSize.x, device->fPenSize.y);
  347.             ::DeleteObject(hrgn);
  348.         }
  349.         else
  350.         {
  351.             if (renderVerb == FW_kFill)
  352.             {
  353.                 plfmRect.right++;
  354.                 plfmRect.bottom++;
  355.             }
  356.     
  357.             ::Ellipse(hDC, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  358.         }
  359.     #endif
  360.     #ifdef FW_BUILD_MAC
  361.         FW_Boolean styleIsDash;
  362.         FW_Boolean styleIsHairline;
  363.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  364.         
  365.         if (renderVerb == FW_kFrame)
  366.         {
  367.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  368.             ::FrameOval(&plfmRect);
  369.         }
  370.         else
  371.         {
  372.             switch (ink->GetTransferMode())
  373.             {
  374.                 case FW_kErase:
  375.                     ::EraseOval(&plfmRect);
  376.                     break;
  377.                     
  378.                 case FW_kInvert:
  379.                     ::InvertOval(&plfmRect);
  380.                     break;
  381.                     
  382.                 default:
  383.                     ::PaintOval(&plfmRect);            
  384.             }
  385.         }
  386.     #endif
  387.     }
  388.     FW_SOM_CATCH
  389. }
  390.                             
  391. //----------------------------------------------------------------------------------------
  392. //    FW_PrivRenderRoundRect
  393. //----------------------------------------------------------------------------------------
  394.  
  395. void SL_API    FW_PrivRenderRoundRect(Environment* ev,
  396.                                     FW_SGraphicContext&     gc,
  397.                                     const FW_SRect&     rect,
  398.                                     const FW_SPoint&     ovalSize,
  399.                                     FW_ERenderVerbs     renderVerb,
  400.                                     FW_HInk             ink,
  401.                                     FW_HStyle             style)
  402. {
  403.     FW_RENDER_PROLOG
  404.     FW_CHECK_RENDER_VERB
  405.     FW_CHECK_INK
  406.     FW_CHECK_STYLE
  407.  
  408.     FW_SOM_TRY
  409.     {
  410.         FW_CPlatformRect plfmRect;
  411.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  412.         FW_FailOnEvError(ev);
  413.             
  414.         FW_CPlatformPoint plfmOvalSize;
  415.         FW_PrivGC_LogicalToDeviceSize(ev, gc, ovalSize.x, ovalSize.y, plfmOvalSize);
  416.         FW_FailOnEvError(ev);
  417.     
  418. #ifdef FW_BUILD_WIN
  419.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  420.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  421.  
  422.         if (frameBrush)
  423.         {
  424.             HRGN hrgn = NULL;
  425.             // There is a bug in Windows. If the size of the round rect is smaller than 1,  we are dead.
  426.             if ((plfmRect.right - plfmRect.left <= 1) || (plfmRect.bottom - plfmRect.top <= 1))
  427.                 hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, 
  428.                                             plfmRect.right + 1, plfmRect.bottom + 1);
  429.             else
  430.                 hrgn = ::CreateRoundRectRgn(plfmRect.left, plfmRect.top, 
  431.                                             plfmRect.right + 1, plfmRect.bottom + 1, 
  432.                                             plfmOvalSize.x, plfmOvalSize.y);
  433.                                             
  434.             ::FrameRgn(hDC, hrgn, device->fGDIBrush.GetBrush(hDC), device->fPenSize.x, device->fPenSize.y);
  435.             ::DeleteObject(hrgn);
  436.         }
  437.         else
  438.         {
  439.             if (renderVerb == FW_kFill)
  440.             {
  441.                 plfmRect.right++;
  442.                 plfmRect.bottom++;
  443.             }
  444.         
  445.             ::RoundRect(hDC, 
  446.                         plfmRect.left, plfmRect.top, 
  447.                         plfmRect.right, plfmRect.bottom,
  448.                         plfmOvalSize.x, plfmOvalSize.y);
  449.         }
  450. #endif
  451. #ifdef FW_BUILD_MAC
  452.         FW_Boolean styleIsDash;
  453.         FW_Boolean styleIsHairline;
  454.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  455.         
  456.         if (renderVerb == FW_kFrame)
  457.         {
  458.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  459.             ::FrameRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  460.         }
  461.         else
  462.         {
  463.             switch (ink->GetTransferMode())
  464.             {
  465.                 case FW_kErase:
  466.                     ::EraseRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  467.                     break;
  468.                 case FW_kInvert:
  469.                     ::InvertRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  470.                     break;
  471.                 default:
  472.                     ::PaintRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);            
  473.             }
  474.         }
  475. #endif
  476.     }
  477.     FW_SOM_CATCH
  478. }
  479.                             
  480. //----------------------------------------------------------------------------------------
  481. //    FW_PrivRenderRoundRect
  482. //----------------------------------------------------------------------------------------
  483.  
  484. void SL_API    FW_PrivRenderArc(Environment* ev,
  485.                             FW_SGraphicContext&     gc,
  486.                             const FW_SRect&         rect, 
  487.                             short                     startAngle, 
  488.                             short                     arcAngle,
  489.                             FW_ERenderVerbs         renderVerb,
  490.                             FW_HInk                 ink,
  491.                             FW_HStyle                 style)
  492. {    
  493.     FW_RENDER_PROLOG
  494.     FW_CHECK_RENDER_VERB
  495.     FW_CHECK_INK
  496.     FW_CHECK_STYLE
  497.     
  498.     FW_SOM_TRY
  499.     {
  500.         FW_CPlatformRect arcRect;
  501.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, arcRect);
  502.         FW_FailOnEvError(ev);
  503.  
  504. #ifdef FW_BUILD_WIN    
  505.         short angle1 = startAngle;
  506.         
  507.         // Normalize the start angle
  508.         angle1 = angle1 % 360;
  509.         if (angle1 < 0)
  510.             angle1 += 360;
  511.             
  512.         // Compute and normalize the end angle
  513.         short angle2 = angle1 + arcAngle;
  514.         if (arcAngle < 0)
  515.         {
  516.             short temp = angle1;
  517.             angle1 = angle2;
  518.             angle2 = temp;
  519.         }
  520.     
  521.         FW_CPlatformPoint endPoint, startPoint;
  522.         FW_PrivCalcArcPoints(arcRect, angle1, endPoint);        // on Windows, arc and pie are drawn counterclockwise
  523.         FW_PrivCalcArcPoints(arcRect, angle2, startPoint);
  524.     
  525.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  526.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  527.  
  528.         if (renderVerb == FW_kFrame)
  529.         {
  530.             if(frameBrush)
  531.             {
  532.                 FW_CRect r = arcRect;
  533.                 ODRgnHandle rgnHandle = ::FW_CreateArcRegion(r, startAngle, arcAngle);
  534.                 ::FrameRgn(hDC, rgnHandle, device->fGDIBrush.GetBrush(hDC), device->fPenSize.x, device->fPenSize.y);
  535.                 ::FW_DisposeRegion(rgnHandle);
  536.             }
  537.             else
  538.             {
  539.                 ::Arc(hDC, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  540.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  541.             }
  542.         }
  543.         else
  544.         {
  545.             arcRect.right++;
  546.             arcRect.bottom++;
  547.             ::Pie(hDC, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  548.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  549.         }
  550. #endif
  551. #ifdef FW_BUILD_MAC
  552.         FW_Boolean styleIsDash;
  553.         FW_Boolean styleIsHairline;
  554.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  555.         
  556.         if (renderVerb == FW_kFrame)
  557.         {
  558.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  559.             ::FrameArc(&arcRect, startAngle, arcAngle);
  560.         }
  561.         else
  562.         {
  563.             switch (ink->GetTransferMode())
  564.             {
  565.                 case FW_kErase:
  566.                     ::EraseArc(&arcRect, startAngle, arcAngle);
  567.                     break;
  568.                 case FW_kInvert:
  569.                     ::InvertArc(&arcRect, startAngle, arcAngle);
  570.                     break;
  571.                 default:
  572.                     ::PaintArc(&arcRect, startAngle, arcAngle);            
  573.             }
  574.         }
  575. #endif
  576.     }
  577.     FW_SOM_CATCH
  578. }
  579.  
  580. //----------------------------------------------------------------------------------------
  581. //     FW_RenderLine
  582. //----------------------------------------------------------------------------------------
  583.  
  584. void SL_API    FW_PrivRenderLine(Environment* ev,
  585.                                 FW_SGraphicContext&     gc,
  586.                                 const FW_SPoint&     start, 
  587.                                 const FW_SPoint&     end,
  588.                                 FW_ERenderVerbs     renderVerb,
  589.                                 FW_HInk             ink,
  590.                                 FW_HStyle             style)
  591. {
  592.     FW_RENDER_PROLOG
  593.     FW_CHECK_RENDER_VERB
  594.     FW_CHECK_INK
  595.     FW_CHECK_STYLE
  596.     
  597.     FW_SOM_TRY
  598.     {
  599.         FW_CPlatformPoint plfmStart;
  600.         FW_PrivGC_LogicalToDevicePoint(ev, gc, start, plfmStart);
  601.         FW_FailOnEvError(ev);
  602.  
  603.     
  604.         FW_CPlatformPoint plfmEnd;
  605.         FW_PrivGC_LogicalToDevicePoint(ev, gc, end, plfmEnd);
  606.         FW_FailOnEvError(ev);
  607.  
  608. #ifdef FW_BUILD_WIN
  609.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  610.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, FW_kFrame);
  611.         
  612.         if (frameBrush)
  613.         {
  614.             int penSizeX = device->fPenSize.x;
  615.             int penHalfX = penSizeX / 2;
  616.             int penSizeY = device->fPenSize.y;
  617.             int penHalfY = penSizeY / 2;
  618.             if (plfmStart.x == plfmEnd.x)
  619.             {
  620.                 device->fGDIBrush.SelectObject(hDC);
  621.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, penSizeX, plfmEnd.y - plfmStart.y, PATCOPY);
  622.             }
  623.             else if (plfmStart.y == plfmEnd.y)
  624.             {
  625.                 device->fGDIBrush.SelectObject(hDC);
  626.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, plfmEnd.x - plfmStart.x, penSizeY, PATCOPY);
  627.             }
  628.             else
  629.             {
  630.                 HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(plfmStart), FW_CPoint(plfmEnd), FW_CPoint(device->fPenSize));        
  631.                 ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  632.                 ::DeleteObject(hRgn);
  633.             }
  634.         }
  635.         else
  636.         {
  637.             ::MoveToEx(hDC, plfmStart.x, plfmStart.y, NULL);
  638.             ::LineTo(hDC, plfmEnd.x, plfmEnd.y);
  639.         }
  640. #endif
  641. #ifdef FW_BUILD_MAC
  642.         FW_Boolean styleIsDash;
  643.         FW_Boolean styleIsHairline;
  644.         MacSelectInkAndStyle(device,
  645.             FW_kLineShape,
  646.             FW_kFrame,                        // We never use FW_kFill for lines
  647.             ink,
  648.             style,
  649.             styleIsDash,
  650.             styleIsHairline);    
  651.  
  652.         short halfPenh = FW_QDGlobals.thePort->pnSize.h / 2;
  653.         short halfPenv = FW_QDGlobals.thePort->pnSize.v / 2;
  654.         
  655.         ::MoveTo(plfmStart.h - halfPenh, plfmStart.v - halfPenv);
  656.         
  657.         {
  658.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  659.             
  660.             if (styleIsDash)
  661.             {
  662.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  663.                 draw.LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  664.             }
  665.             else
  666.             {
  667.                 ::LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  668.             }
  669.         }
  670. #endif
  671.     }
  672.     FW_SOM_CATCH
  673. }
  674.  
  675. //----------------------------------------------------------------------------------------
  676. //    FW_PrivRenderRegion
  677. //----------------------------------------------------------------------------------------
  678.  
  679. void SL_API    FW_PrivRenderRegion(Environment* ev,
  680.                                 FW_SGraphicContext&     gc,
  681.                                 ODShape*                 odShape,
  682.                                 FW_ERenderVerbs         renderVerb,
  683.                                 FW_HInk                 ink,
  684.                                 FW_HStyle                 style)
  685. {
  686.     FW_RENDER_PROLOG
  687.     FW_CHECK_RENDER_VERB
  688.     FW_CHECK_INK
  689.     FW_CHECK_STYLE
  690.     
  691.     FW_SOM_TRY
  692.     {
  693.         ODShape* deviceShape = FW_PrivGC_LogicalToDeviceShape(ev, gc, odShape);
  694.         FW_FailOnEvError(ev);
  695.         
  696.         ODRgnHandle rgnHandle = ::FW_GetShapeRegion(ev, deviceShape);
  697.         FW_ASSERT(rgnHandle != NULL);
  698.  
  699. #ifdef FW_BUILD_WIN
  700.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  701.         FW_ERenderVerbs localVerb = renderVerb == FW_kFrame ? FW_kFill : renderVerb;
  702.         device->SelectInkAndStyle(ink, style, FW_kGeometricShapeWithInvert, localVerb);
  703.     
  704.         switch (renderVerb)
  705.         {
  706.             case FW_kFrame:
  707.                 ::FrameRgn(hDC, rgnHandle, device->fGDIBrush.GetBrush(hDC), device->fPenSize.x, device->fPenSize.y);
  708.                 break;
  709.     
  710.             case FW_kFill:
  711.                 if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite || ink->GetTransferMode() == FW_kSystemHilite)
  712.                     ::InvertRgn(hDC, rgnHandle);
  713.                 else
  714.                     ::FillRgn(hDC, rgnHandle, device->fGDIBrush.GetBrush(hDC));
  715.                 break;
  716.         }
  717. #endif
  718. #ifdef FW_BUILD_MAC
  719.         FW_Boolean styleIsDash;
  720.         FW_Boolean styleIsHairline;
  721.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);        
  722.         
  723.         if (renderVerb == FW_kFrame)
  724.         {
  725.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  726.             ::FrameRgn(rgnHandle);
  727.         }
  728.         else
  729.         {
  730.             switch (ink->GetTransferMode())
  731.             {
  732.                 case FW_kErase:
  733.                     ::EraseRgn(rgnHandle);
  734.                     break;
  735.                 case FW_kInvert:
  736.                     ::InvertRgn(rgnHandle);
  737.                     break;
  738.                 default:
  739.                     ::PaintRgn(rgnHandle);            
  740.             }
  741.         }
  742. #endif
  743.         deviceShape->Release(ev);
  744.     }
  745.     FW_SOM_CATCH
  746. }
  747.  
  748. //----------------------------------------------------------------------------------------
  749. //    FW_PrivRenderPolygon
  750. //----------------------------------------------------------------------------------------
  751.  
  752. void SL_API    FW_PrivRenderPolygon(Environment* ev,
  753.                                 FW_SGraphicContext&     gc,
  754.                                 FW_HPolygon             polygon,
  755.                                 FW_ERenderVerbs         renderVerb,
  756.                                 FW_Boolean                 autoCloseFrame,
  757.                                 FW_HInk                 ink,
  758.                                 FW_HStyle                 style)
  759. {
  760.     FW_RENDER_PROLOG
  761.     FW_CHECK_RENDER_VERB
  762.     FW_CHECK_INK
  763.     FW_CHECK_STYLE
  764.     
  765.     FW_SOM_TRY
  766.     {
  767.         long count = polygon->GetCount();
  768.         const FW_SPoint* points = polygon->GetPoints();
  769.  
  770. #ifdef FW_BUILD_WIN
  771.         // Convert points to platform points
  772.         unsigned long plfmCount = count;
  773.         FW_Boolean needClose = FALSE;
  774.         if (renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  775.         {
  776.             ++ plfmCount;
  777.             needClose = TRUE;
  778.         }
  779.         
  780.         FW_CPlatformPoint* plfmPoints = new FW_CPlatformPoint[plfmCount];
  781.         for (long i = 0; i < count; i ++)
  782.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[i], plfmPoints[i]);
  783.     
  784.         if (needClose)
  785.             plfmPoints[plfmCount - 1] = plfmPoints[0];
  786.     
  787.         // Prepare the graphics device
  788.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  789.     
  790.         int penSizeX = device->fPenSize.x;
  791.         int penHalfX = penSizeX / 2;
  792.         int penSizeY = device->fPenSize.y;
  793.         int penHalfY = penSizeY / 2;
  794.         
  795.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  796.     
  797.         // Render the polygon
  798.         switch (renderVerb)
  799.         {
  800.             case FW_kFrame:
  801.                 if(frameBrush)
  802.                 {
  803.                     // Doing it like this is way, way faster than creating a polygon
  804.                     // region for the whole thing and framing it
  805.                     FW_CPlatformPoint pt0, pt1;
  806.                     BOOL bBrushSelected = FALSE;
  807.     
  808.                     for(unsigned long p = 0; p < plfmCount - 1; p ++)
  809.                     {
  810.                         pt0 = plfmPoints[p];
  811.                         pt1 = plfmPoints[p + 1];
  812.                         
  813.                         if (pt0.x == pt1.x)
  814.                         {
  815.                             if (!bBrushSelected)
  816.                             {
  817.                                 device->fGDIBrush.SelectObject(hDC);
  818.                                 bBrushSelected = TRUE;
  819.                             }
  820.     
  821.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, penSizeX, pt1.y - pt0.y, PATCOPY);
  822.                         }
  823.                         else if (pt0.y == pt1.y)
  824.                         {
  825.                             if (!bBrushSelected)
  826.                             {
  827.                                 device->fGDIBrush.SelectObject(hDC);
  828.                                 bBrushSelected = TRUE;
  829.                             }
  830.     
  831.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, pt1.x - pt0.x, penSizeY, PATCOPY);
  832.                         }
  833.                         else
  834.                         {
  835.                             HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(pt0), FW_CPoint(pt1), FW_CPoint(device->fPenSize));
  836.                             ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  837.                             ::DeleteObject(hRgn);
  838.                         }
  839.                     }
  840.                 }
  841.                 else
  842.                 {
  843.                     ::Polyline(hDC, plfmPoints, plfmCount);
  844.                 }
  845.                 break;
  846.     
  847.             case FW_kFill:
  848.                 ::Polygon(hDC, plfmPoints, plfmCount);
  849.                 break;
  850.         }
  851.         
  852.         delete[] plfmPoints;
  853. #endif
  854. #ifdef FW_BUILD_MAC
  855.         // Create a polygon
  856.         GrafPtr savePort;
  857.         ::GetPort(&savePort);
  858.         ::SetPort(FW_gScratchPort);
  859.         PolyHandle polyHandle = ::OpenPoly();
  860.         
  861.         if(polyHandle == NULL)
  862.         {
  863.             ::SetPort(savePort);
  864.             FW_Failure(FW_xMemoryExhausted);
  865.         }
  866.     
  867.         FW_CPlatformPoint plfmPoint;
  868.         FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  869.         FW_FailOnEvError(ev);
  870.         
  871.         ::MoveTo(plfmPoint.h, plfmPoint.v);
  872.     
  873.         for(long i = 1; i < count; i ++)
  874.         {
  875.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[i], plfmPoint);
  876.             FW_FailOnEvError(ev);
  877.             
  878.             ::LineTo(plfmPoint.h, plfmPoint.v);
  879.         }
  880.         
  881.         // Close the polygon if needed
  882.         if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  883.         {
  884.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  885.             FW_FailOnEvError(ev);
  886.             
  887.             ::LineTo(plfmPoint.h, plfmPoint.v);
  888.         }
  889.     
  890.         ::ClosePoly();
  891.         ::SetPort(savePort);
  892.     
  893.         // Prepare the grafport
  894.         FW_Boolean styleIsDash;
  895.         FW_Boolean styleIsHairline;
  896.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);        
  897.         
  898.         // Render the polygon
  899.         if (renderVerb == FW_kFrame)
  900.         {
  901.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  902.             
  903.             if (styleIsDash)
  904.             {
  905.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  906.                 short nPolyCount = ((*polyHandle)->polySize - 10) / sizeof(Point);
  907.                 ::MoveTo((*polyHandle)->polyPoints[0].h, (*polyHandle)->polyPoints[0].v);
  908.                 for (short n = 1; n < nPolyCount; ++ n)
  909.                     draw.LineTo((*polyHandle)->polyPoints[n].h, (*polyHandle)->polyPoints[n].v);
  910.             }
  911.             else
  912.             {
  913.                 ::FramePoly(polyHandle);
  914.             }
  915.         }
  916.         else
  917.         {
  918.             switch (ink->GetTransferMode())
  919.             {
  920.                 case FW_kErase:
  921.                     ::ErasePoly(polyHandle);
  922.                     break;
  923.                 case FW_kInvert:
  924.                     ::InvertPoly(polyHandle);
  925.                     break;
  926.                 default:
  927.                     ::PaintPoly(polyHandle);            
  928.             }
  929.         }
  930.     
  931.         ::KillPoly(polyHandle);
  932. #endif
  933.     }
  934.     FW_SOM_CATCH
  935. }                                            
  936.  
  937. //----------------------------------------------------------------------------------------
  938. //    FW_PrivRenderTextString
  939. //----------------------------------------------------------------------------------------
  940.  
  941. void SL_API    FW_PrivRenderTextString(Environment* ev,
  942.                                     FW_SGraphicContext&    gc,
  943.                                     FW_HString            string,
  944.                                     const FW_SPoint&    position,
  945.                                     FW_TextAlignment    textAlignment,
  946.                                     FW_ERenderVerbs        renderVerb,
  947.                                     FW_HInk             ink,
  948.                                     FW_HFont             font)
  949. {
  950.     FW_SOM_TRY
  951.     {
  952.         FW_CPrivTextBuffer buffer(string);
  953.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  954.     }
  955.     FW_SOM_CATCH
  956. }
  957.                                 
  958. //----------------------------------------------------------------------------------------
  959. //    FW_PrivRenderTextReader
  960. //----------------------------------------------------------------------------------------
  961.  
  962. void SL_API    FW_PrivRenderTextReader(Environment* ev,
  963.                                     FW_SGraphicContext&    gc,
  964.                                     FW_HTextReader        reader,
  965.                                     const FW_SPoint&    position,
  966.                                     FW_TextAlignment    textAlignment,
  967.                                     FW_ERenderVerbs        renderVerb,
  968.                                     FW_HInk                ink,
  969.                                     FW_HFont            font)
  970. {
  971.     FW_SOM_TRY
  972.     {
  973.         FW_CPrivTextBuffer buffer(reader);
  974.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  975.     }
  976.     FW_SOM_CATCH
  977. }
  978.  
  979. //----------------------------------------------------------------------------------------
  980. //    PrivRenderTextBuffer
  981. //----------------------------------------------------------------------------------------
  982.  
  983. static void    PrivRenderTextBuffer(Environment* ev,
  984.                                 FW_SGraphicContext&    gc,
  985.                                 FW_CPrivTextBuffer*    textBuffer,
  986.                                 const FW_SPoint&    position,
  987.                                 FW_TextAlignment    textAlignment,
  988.                                 FW_ERenderVerbs        renderVerb,
  989.                                 FW_HInk                ink,
  990.                                 FW_HFont            font)
  991. {    
  992.     FW_RENDER_PROLOG
  993.     FW_CHECK_RENDER_VERB
  994.     FW_CHECK_FONT
  995.     FW_CHECK_INK
  996.  
  997.     FW_ASSERT(textBuffer != NULL);
  998.     if (textBuffer->IsDone())    // No text to draw
  999.         return;
  1000.  
  1001.     FW_CPlatformPoint plfmPos;
  1002.     FW_PrivGC_LogicalToDevicePoint(ev, gc, position, plfmPos);
  1003.     FW_FailOnEvError(ev);
  1004.  
  1005.     // ----- RenderText only cares about the first line -----    
  1006.     const char* text;
  1007.     FW_ByteCount count;
  1008.     textBuffer->GetCurrentLine(text, count);
  1009.  
  1010. #ifdef FW_BUILD_WIN
  1011.     HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1012.     device->SelectInkAndFont(ink, font);
  1013.         
  1014.     // ----- Set the text alignment - always use TA_UPDATECP (see below)
  1015.     TEXTMETRIC tm;
  1016.     UINT newAlign = TA_UPDATECP;
  1017.     
  1018.     switch (textAlignment & FW_kPrivTextAlignVertAlignMask)
  1019.     {
  1020.         case FW_kTextAlignTop:
  1021.             newAlign |= TA_TOP;
  1022.             break;
  1023.             
  1024.         case FW_kTextAlignBottom:
  1025.             newAlign |= TA_BOTTOM;
  1026.             break;
  1027.             
  1028.         case FW_kTextAlignVCenter:
  1029.             ::GetTextMetrics(hDC, &tm);
  1030.             plfmPos.y -= (tm.tmHeight - tm.tmInternalLeading) / 2;
  1031.             break;
  1032.             
  1033.         case FW_kTextAlignBaseLine:
  1034.             newAlign |= TA_BASELINE;
  1035.             break;
  1036.     }
  1037.  
  1038.     switch (textAlignment & FW_kPrivTextAlignHorzAlignMask)
  1039.     {
  1040.         case FW_kTextAlignLeft:
  1041.             newAlign |= TA_LEFT;
  1042.             break;
  1043.             
  1044.         case FW_kTextAlignRight:
  1045.             newAlign |= TA_RIGHT;
  1046.             break;
  1047.             
  1048.         case FW_kTextAlignHCenter:
  1049.             newAlign |= TA_CENTER;
  1050.             break;
  1051.     }
  1052.     
  1053.     // It is necessary to use TA_UPDATECP because the next call may want to use
  1054.     //    FW_kTextAlignUseCurrentPos.  However, TA_UPDATECP also means "use CP", so
  1055.     //    if this is not what the user wants, we should move to the right pos first
  1056.  
  1057.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseSpecifiedPos)
  1058.         ::MoveToEx(hDC, plfmPos.x, plfmPos.y, NULL);
  1059.  
  1060.     ::SetTextAlign(hDC, newAlign);
  1061.     ::TextOut(hDC,
  1062.             0, 0,        // we use TA_UPDATECP, remember?
  1063.             text,
  1064.             count);
  1065.             
  1066.     ::SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);        // restore the flags
  1067. #endif
  1068. #ifdef FW_BUILD_MAC
  1069.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1070.     device->SelectFont(font, TRUE);        // SetInGrafPort called by SelectFont
  1071.  
  1072.     // ----- The Mac only knows to draw text from the baseline, so we need to do some adjustment
  1073.     FW_CPlatformPoint plfmTextPos = MacCalcTextPosition(device, count, text, textAlignment, plfmPos);
  1074.     
  1075.     // ----- Draw the text
  1076.     ::MoveTo(plfmTextPos.h, plfmTextPos.v);
  1077.     ::DrawText(text, 0, count);
  1078.  
  1079.     // ----- StrikeOut if necessary
  1080.     if ((font->GetFontStyle() & FW_kStrikeOut) != 0)
  1081.         MacStrikeOut(device, plfmTextPos.h, plfmTextPos.v);
  1082. #endif
  1083. }
  1084.                                 
  1085. //----------------------------------------------------------------------------------------
  1086. //    FW_PrivRenderTextBoxString
  1087. //----------------------------------------------------------------------------------------
  1088.  
  1089. FW_Fixed SL_API FW_PrivRenderTextBoxString(Environment* ev,
  1090.                                             FW_SGraphicContext&    gc,
  1091.                                             FW_HString            string, 
  1092.                                             const FW_SRect&        box,
  1093.                                             FW_TextBoxOptions    options,
  1094.                                             FW_ERenderVerbs        renderVerb,
  1095.                                             FW_HInk                ink,
  1096.                                             FW_HFont            font)
  1097. {
  1098.     FW_SOM_TRY
  1099.     {
  1100.         FW_CPrivTextBuffer buffer(string);
  1101.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1102.     }
  1103.     FW_SOM_CATCH
  1104.     return FW_kFixed0;
  1105. }
  1106.  
  1107. //----------------------------------------------------------------------------------------
  1108. //    FW_PrivRenderTextBoxReader
  1109. //----------------------------------------------------------------------------------------
  1110.  
  1111. FW_Fixed SL_API FW_PrivRenderTextBoxReader(Environment* ev,
  1112.                                             FW_SGraphicContext&    gc,
  1113.                                             FW_HTextReader        reader, 
  1114.                                             const FW_SRect&        box,
  1115.                                             FW_TextBoxOptions    options,
  1116.                                             FW_ERenderVerbs        renderVerb,
  1117.                                             FW_HInk                ink,
  1118.                                             FW_HFont            font)
  1119. {
  1120.     FW_SOM_TRY
  1121.     {
  1122.         FW_CPrivTextBuffer buffer(reader);
  1123.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1124.     }
  1125.     FW_SOM_CATCH
  1126.     return FW_kFixed0;
  1127. }
  1128.  
  1129. //----------------------------------------------------------------------------------------
  1130. //    PrivRenderTextBoxBuffer
  1131. //----------------------------------------------------------------------------------------
  1132.  
  1133. static FW_Fixed    PrivRenderTextBoxBuffer(Environment* ev,
  1134.                                         FW_SGraphicContext& gc,
  1135.                                         FW_CPrivTextBuffer* textBuffer, 
  1136.                                         const FW_SRect& box,
  1137.                                         FW_TextBoxOptions options,
  1138.                                         FW_ERenderVerbs renderVerb,
  1139.                                         FW_HInk ink,
  1140.                                         FW_HFont font)
  1141. {
  1142.     FW_RENDER_PROLOG
  1143.     FW_CHECK_FONT
  1144.     FW_CHECK_INK
  1145.     
  1146.     FW_ASSERT(textBuffer != NULL);
  1147.     if (renderVerb == FW_kNoRendering || textBuffer->IsDone())
  1148.         return box.top;
  1149.         
  1150.     FW_CPlatformRect plfmBox;
  1151.     FW_PrivGC_LogicalToDeviceRect(ev, gc, box, plfmBox);
  1152.     FW_FailOnEvError(ev);
  1153.  
  1154. #ifdef FW_BUILD_WIN
  1155.     device->SelectInkAndFont(ink, font);
  1156. #endif
  1157. #ifdef FW_BUILD_MAC
  1158.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1159.     device->SelectFont(font, TRUE);
  1160. #endif
  1161.  
  1162.     FW_PlatformCoordinate bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, TRUE, font);
  1163.  
  1164.     if (bottom != plfmBox.bottom)
  1165.     {
  1166.         FW_CPlatformPoint pt(0, bottom);
  1167.         FW_CPoint cPt;
  1168.         FW_PrivGC_DeviceToLogicalPoint(ev, gc, pt, cPt);
  1169.         FW_FailOnEvError(ev);
  1170.         return cPt.y;
  1171.     }
  1172.     
  1173.     return box.bottom;
  1174. }
  1175.                                 
  1176. //----------------------------------------------------------------------------------------
  1177. //    FW_PrivTextBoxSizeString
  1178. //----------------------------------------------------------------------------------------
  1179.  
  1180. void SL_API FW_PrivTextBoxSizeString(Environment* ev,
  1181.                                     FW_SGraphicContext&    gc,
  1182.                                     FW_HString            string, 
  1183.                                     FW_HFont            font,
  1184.                                     FW_TextBoxOptions    options,
  1185.                                     FW_SRect&            textBox)
  1186. {
  1187.     FW_SOM_TRY
  1188.     {
  1189.         FW_CPrivTextBuffer buffer(string);
  1190.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1191.     }
  1192.     FW_SOM_CATCH
  1193. }
  1194.  
  1195. //----------------------------------------------------------------------------------------
  1196. //    FW_PrivTextBoxSizeReader
  1197. //----------------------------------------------------------------------------------------
  1198.  
  1199. void SL_API FW_PrivTextBoxSizeReader(Environment* ev,
  1200.                                     FW_SGraphicContext&    gc,
  1201.                                     FW_HTextReader        reader, 
  1202.                                     FW_HFont            font,
  1203.                                     FW_TextBoxOptions    options,
  1204.                                     FW_SRect&            textBox)
  1205. {
  1206.     FW_SOM_TRY
  1207.     {
  1208.         FW_CPrivTextBuffer buffer(reader);
  1209.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1210.     }
  1211.     FW_SOM_CATCH
  1212. }
  1213.  
  1214. //----------------------------------------------------------------------------------------
  1215. //    PrivTextBoxSizeBuffer
  1216. //----------------------------------------------------------------------------------------
  1217.  
  1218. static void PrivTextBoxSizeBuffer(Environment* ev,
  1219.                                     FW_SGraphicContext& gc,
  1220.                                     FW_CPrivTextBuffer *textBuffer, 
  1221.                                     FW_HFont font,
  1222.                                     FW_TextBoxOptions options,
  1223.                                     FW_SRect& textBox)
  1224. {
  1225.     FW_RENDER_PROLOG
  1226.     FW_CHECK_FONT
  1227.     
  1228.     FW_ASSERT((const void*)font != NULL);
  1229.     FW_ASSERT(textBuffer != NULL);
  1230.  
  1231.     FW_CPlatformRect plfmBox;
  1232.     FW_PrivGC_LogicalToDeviceRect(ev, gc, textBox, plfmBox);
  1233.     FW_FailOnEvError(ev);
  1234.  
  1235.     if (textBuffer->IsDone())
  1236.     {
  1237.         plfmBox.bottom = plfmBox.top;
  1238.     }
  1239.     else
  1240.     {
  1241.         device->SelectFont(font, TRUE);                    // TRUE: scale
  1242.         plfmBox.bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, FALSE, font);    // FALSE: don't draw
  1243.     }
  1244.  
  1245.     FW_CPoint textBoxSize;
  1246.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmBox.right, plfmBox.bottom, textBoxSize);
  1247.     FW_FailOnEvError(ev);
  1248.     
  1249.     textBox.right    = textBox.left + textBoxSize.x;
  1250.     textBox.bottom    = textBox.top  + textBoxSize.y;
  1251. }
  1252.  
  1253. //----------------------------------------------------------------------------------------
  1254. //    FW_PrivCalcTextExtentString
  1255. //----------------------------------------------------------------------------------------
  1256.  
  1257. void SL_API FW_PrivCalcTextExtentString(Environment* ev,
  1258.                                         FW_SGraphicContext&        gc,
  1259.                                         FW_HString                 string,
  1260.                                         FW_HFont                 font,
  1261.                                         FW_SPoint&                 textExtent)
  1262. {
  1263.     FW_SOM_TRY
  1264.     {
  1265.         FW_CPrivTextBuffer buffer(string);
  1266.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1267.     }
  1268.     FW_SOM_CATCH
  1269. }
  1270.  
  1271. //----------------------------------------------------------------------------------------
  1272. //    FW_PrivCalcTextExtentReader
  1273. //----------------------------------------------------------------------------------------
  1274.  
  1275. void SL_API FW_PrivCalcTextExtentReader(Environment* ev,
  1276.                                         FW_SGraphicContext&    gc,
  1277.                                         FW_HTextReader        reader,
  1278.                                         FW_HFont            font, 
  1279.                                         FW_SPoint&            textExtent)
  1280. {
  1281.     FW_SOM_TRY
  1282.     {
  1283.         FW_CPrivTextBuffer buffer(reader);
  1284.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1285.     }
  1286.     FW_SOM_CATCH
  1287. }
  1288.  
  1289. //----------------------------------------------------------------------------------------
  1290. //    PrivTextExtentBuffer
  1291. //----------------------------------------------------------------------------------------
  1292.  
  1293. static void PrivTextExtentBuffer(Environment* ev,
  1294.                                 FW_SGraphicContext& gc,
  1295.                                 FW_CPrivTextBuffer* textBuffer,
  1296.                                 FW_HFont font, 
  1297.                                 FW_SPoint& textExtent)
  1298. {
  1299.     FW_RENDER_PROLOG
  1300.     FW_CHECK_FONT
  1301.  
  1302.     if (textBuffer->IsDone())
  1303.     {
  1304.         textExtent = FW_kZeroPoint;
  1305.         return;
  1306.     }
  1307.     
  1308.     device->SelectFont(font, TRUE);
  1309.     
  1310.     // ----- TextExtent only cares about the first line -----    
  1311.     FW_ByteCount count;
  1312.     const char* text;
  1313.     textBuffer->GetCurrentLine(text, count);
  1314.  
  1315. #ifdef FW_BUILD_WIN
  1316.     HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1317.     SIZE size;
  1318.  
  1319.     ::GetTextExtentPoint32(hDC, text, count, &size);
  1320.     FW_CPlatformPoint plfmExtent(size.cx, size.cy);
  1321. #endif
  1322. #ifdef FW_BUILD_MAC
  1323.     FontInfo fi;
  1324.     ::GetFontInfo(&fi);
  1325.     
  1326.     FW_CPlatformPoint plfmExtent(
  1327.             ::TextWidth(text, 0, count),
  1328.             fi.ascent + fi.descent);
  1329. #endif
  1330.  
  1331.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmExtent.X(), plfmExtent.Y(), textExtent);
  1332.     FW_FailOnEvError(ev);
  1333. }
  1334.  
  1335. //----------------------------------------------------------------------------------------
  1336. //    FW_PrivRenderPicture
  1337. //----------------------------------------------------------------------------------------
  1338.  
  1339. void SL_API    FW_PrivRenderPicture(Environment* ev,
  1340.                                 FW_SGraphicContext& gc,
  1341.                                 FW_HPicture picture,
  1342.                                 const FW_SRect& dstRect,
  1343.                                 FW_ERenderVerbs renderVerb)
  1344. {
  1345.     FW_RENDER_PROLOG
  1346.     FW_CHECK_RENDER_VERB
  1347.     
  1348.     FW_SOM_TRY
  1349.     {
  1350.         FW_ASSERT(picture != NULL);
  1351.         FW_PlatformPict pict = picture->GetPlatformPict();
  1352.         FW_CPlatformRect plfmRect;
  1353.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmRect);
  1354.         FW_FailOnEvError(ev);
  1355.     
  1356. #ifdef FW_BUILD_WIN
  1357.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1358.  
  1359.         ::PlayEnhMetaFile(hDC, pict, &plfmRect);
  1360. #endif
  1361. #ifdef FW_BUILD_MAC
  1362.         ::DrawPicture(pict, &plfmRect);
  1363. #endif
  1364.     }
  1365.     FW_SOM_CATCH
  1366. }
  1367.  
  1368. //----------------------------------------------------------------------------------------
  1369. //    FW_PrivRenderBitmap
  1370. //----------------------------------------------------------------------------------------
  1371.  
  1372. void SL_API    FW_PrivRenderBitmap(Environment* ev,
  1373.                                 FW_SGraphicContext& gc,
  1374.                                 FW_HBitmap bitmap,
  1375.                                 const FW_SRect& srcRect,
  1376.                                 const FW_SRect& dstRect,
  1377.                                 FW_ERenderVerbs renderVerb,
  1378.                                 FW_HInk ink)
  1379. {
  1380.     FW_CHECK_RENDER_VERB
  1381.  
  1382.     // If erase, invert or hilite is used then simply erase/invert/hilite the dst Rectangle
  1383.     FW_TransferModes transferMode = ink->GetTransferMode();
  1384.     if (transferMode == FW_kErase || transferMode == FW_kInvert || transferMode == FW_kHilite || transferMode == FW_kSystemHilite)
  1385.     {
  1386.         FW_CStyle style(FW_kNormalStyle);
  1387.         FW_PrivRenderRect(ev, gc, dstRect, FW_kFill, ink, style);
  1388.         return;
  1389.     }
  1390.  
  1391.     FW_RENDER_PROLOG
  1392.  
  1393.     FW_ASSERT(bitmap != NULL);
  1394.     
  1395.     FW_SOM_TRY
  1396.     {
  1397.         // Convert source and destination rectangles
  1398.         FW_CPlatformRect plfmDstRect;
  1399.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmDstRect);
  1400.         FW_FailOnEvError(ev);
  1401.         
  1402.         FW_CPlatformRect plfmSrcRect = srcRect;    
  1403.         
  1404. #ifdef FW_BUILD_WIN
  1405.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1406.     
  1407.         ::SetTextColor(hDC, ink->GetForeColor());
  1408.         ::SetBkColor(hDC, ink->GetBackColor());
  1409.  
  1410.         HBITMAP plfmBitmap = bitmap->GetPlatformBitmap();
  1411.     
  1412.         HDC memoryDC = ::CreateCompatibleDC(hDC);
  1413.         HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, plfmBitmap);
  1414.     
  1415.         HPALETTE hPal = bitmap->GetPalette();
  1416.         HPALETTE hPalOld = NULL;
  1417.         if (hPal != NULL)
  1418.         {
  1419.             hPalOld = ::SelectPalette(hDC, hPal, FALSE);
  1420.             ::RealizePalette(hDC);
  1421.         }
  1422.     
  1423.         ::StretchBlt(hDC,
  1424.                     plfmDstRect.left,
  1425.                     plfmDstRect.top,
  1426.                     plfmDstRect.right - plfmDstRect.left,
  1427.                     plfmDstRect.bottom - plfmDstRect.top,
  1428.                     memoryDC,
  1429.                     plfmSrcRect.left, 
  1430.                     plfmSrcRect.top,
  1431.                     plfmSrcRect.right - plfmSrcRect.left,
  1432.                     plfmSrcRect.bottom - plfmSrcRect.top,
  1433.                     FW_PrivWinConvertRasterOp(ink->GetTransferMode()));
  1434.     
  1435.         if (hPalOld)
  1436.             ::SelectPalette(hDC, hPalOld, TRUE);
  1437.     
  1438.         ::SelectObject(memoryDC, oldBitmap);
  1439.         ::DeleteDC(memoryDC);
  1440. #endif
  1441. #ifdef FW_BUILD_MAC    
  1442.         device->SelectInk(ink, FW_kImageShape, FW_kFill);    // Never use FW_kFrame for bitmap
  1443.         device->SetInGrafPort();
  1444.  
  1445.         PixMapHandle pmh = bitmap->MacLockPixels();
  1446.         ::CopyBits((BitMap*)*pmh, &FW_QDGlobals.thePort->portBits, 
  1447.                     &plfmSrcRect, &plfmDstRect, 
  1448.                     FW_PrivMacGetMacTransferMode(ink->GetTransferMode()), NULL);
  1449.         bitmap->MacUnlockPixels();
  1450. #endif
  1451.     }
  1452.     FW_SOM_CATCH
  1453. }
  1454.  
  1455. //----------------------------------------------------------------------------------------
  1456. //    FW_PrivRenderIcon
  1457. //----------------------------------------------------------------------------------------
  1458.  
  1459. void SL_API    FW_PrivRenderIcon(Environment* ev,
  1460.                             FW_SGraphicContext& gc,
  1461.                               FW_HIcon icon,
  1462.                             const FW_SRect& rect,
  1463.                             FW_RenderIconTransform transform,
  1464.                             FW_RenderIconAlignment alignment,
  1465.                             FW_ERenderVerbs renderVerb)
  1466. {
  1467.     FW_RENDER_PROLOG
  1468.     FW_CHECK_RENDER_VERB
  1469.  
  1470.     FW_ASSERT(icon != NULL);
  1471.     
  1472.     FW_SOM_TRY
  1473.     {
  1474.         FW_PlatformIcon hIcon = icon->GetPlatformIcon();
  1475.     
  1476.         FW_PlatformRect plfmDstRect;
  1477.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmDstRect);
  1478.         FW_FailOnEvError(ev);
  1479.                 
  1480. #ifdef FW_BUILD_WIN
  1481.         HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1482.         FW_CPoint iconSize;
  1483.         icon->GetIconSize(iconSize);
  1484.         
  1485.         short xSize = iconSize.IntX(), ySize = iconSize.IntY();
  1486.         
  1487.         // Horizontal alignment
  1488.         if (alignment & FW_kIconAlignCenter)
  1489.         {
  1490.             plfmDstRect.left = (plfmDstRect.right + plfmDstRect.left - xSize) / 2;
  1491.             plfmDstRect.right = plfmDstRect.left + xSize;
  1492.         }
  1493.         else if (alignment & FW_kIconAlignLeft)
  1494.         {
  1495.             plfmDstRect.right = plfmDstRect.left + xSize;
  1496.         }
  1497.         else if (alignment & FW_kIconAlignRight)
  1498.         {
  1499.             plfmDstRect.left = plfmDstRect.right - xSize;
  1500.         }
  1501.                 
  1502.         // Vertical alignment
  1503.         if (alignment & FW_kIconAlignVCenter)
  1504.         {
  1505.             plfmDstRect.top = (plfmDstRect.bottom + plfmDstRect.top - ySize) / 2;
  1506.             plfmDstRect.bottom = plfmDstRect.top + ySize;
  1507.         }
  1508.         else if (alignment & FW_kIconAlignTop)
  1509.         {
  1510.             plfmDstRect.bottom = plfmDstRect.top + ySize;
  1511.         }
  1512.         else if (alignment & FW_kIconAlignBottom)
  1513.         {
  1514.             plfmDstRect.top = plfmDstRect.bottom - ySize;
  1515.         }
  1516.         
  1517.         // [HLX] Need to support tranform
  1518.         ::DrawIconEx(hDC, plfmDstRect.left, plfmDstRect.top, hIcon,
  1519.             plfmDstRect.right - plfmDstRect.left,
  1520.             plfmDstRect.bottom - plfmDstRect.top,
  1521.             0, NULL, DI_NORMAL);
  1522. #endif
  1523.  
  1524. #ifdef FW_BUILD_MAC
  1525.         FW_PrivMacSetStdColors();        
  1526.         ::PlotIconSuite(&plfmDstRect, alignment, transform, hIcon);
  1527. #endif
  1528.     }
  1529.     FW_SOM_CATCH
  1530. }
  1531.  
  1532. //========================================================================================
  1533. // Local helpers
  1534. //========================================================================================
  1535.  
  1536. //----------------------------------------------------------------------------------------
  1537. //    PrivTextBox
  1538. //----------------------------------------------------------------------------------------
  1539.  
  1540. static FW_PlatformCoordinate     PrivTextBox(Environment* ev,
  1541.                                     FW_CPrivGraphicsDevice* device,
  1542.                                     FW_CPrivTextBuffer *textBuffer, 
  1543.                                     const FW_CPlatformRect& box,
  1544.                                     FW_TextBoxOptions options,
  1545.                                     FW_Boolean draw,
  1546.                                     FW_HFont font)
  1547. {
  1548. FW_UNUSED(ev);
  1549.  
  1550.     if (textBuffer->IsDone())
  1551.         return box.top;
  1552.  
  1553.     // ----- Check options for consistency
  1554.     FW_TextBoxOptions opt = options;
  1555.  
  1556.     if (!draw)
  1557.         opt &= ~FW_kTextBoxClipToBox;
  1558.     
  1559.     if ((opt & FW_kTextBoxSingleLine) != 0)
  1560.     {
  1561.         opt &= ~FW_kTextBoxWordWrap;
  1562.         opt &= ~FW_kTextBoxWordBreak;
  1563.     }
  1564.     
  1565.     if ((opt & FW_kTextBoxWordWrap) != 0)
  1566.     {
  1567.         opt &= ~FW_kTextBoxJustifyBottom;
  1568.         opt &= ~FW_kTextBoxJustifyVCenter;
  1569.     }
  1570.  
  1571.     FW_CharacterPosition segStart;        // start of the current string segment
  1572.     FW_CharacterCount segLen;            // its length (charcter count)
  1573.     FW_PlatformCoordinate actualWidth;    // its actual width (pixels)
  1574.     FW_PlatformCoordinate maxWidth = box.right - box.left;
  1575.  
  1576.     FW_Boolean bClip = (opt & FW_kTextBoxClipToBox) != 0;
  1577.  
  1578. #ifdef FW_BUILD_WIN
  1579.     // ----- Set the clipping region if we need to
  1580.     HDC hDC = device->GetPlatformCanvas()->GetDC(ev);
  1581.     int savedDC = 0;
  1582.  
  1583.     if (bClip)
  1584.     {
  1585.         savedDC = ::SaveDC(hDC);
  1586.         ::IntersectClipRect(hDC, 
  1587.                             box.left, box.top, 
  1588.                             box.right, box.bottom);
  1589.     }
  1590.  
  1591.     // ----- Get the font height
  1592.     TEXTMETRIC textMetric;
  1593.     ::GetTextMetrics(hDC, &textMetric);
  1594.     FW_PlatformCoordinate fontHeight = textMetric.tmHeight + textMetric.tmExternalLeading;
  1595.  
  1596.     FW_PlatformCoordinate drawPosY = box.top;
  1597.     FW_PlatformCoordinate drawPosX = box.left;
  1598. #endif
  1599. #ifdef FW_BUILD_MAC
  1600.     // ----- Set the clipping region if we need to
  1601.     RgnHandle oldClipRgn = 0;
  1602.     if (bClip)
  1603.     {
  1604.         oldClipRgn = device->GetClip();
  1605.         device->IntersectClipRect(ev, box);
  1606.     }
  1607.  
  1608.     // ----- Get the font height -----
  1609.     FontInfo fi;
  1610.     ::GetFontInfo(&fi);
  1611.     FW_PlatformCoordinate fontHeight = fi.ascent + fi.descent + fi.leading;
  1612.  
  1613.     FW_PlatformCoordinate drawPosY = box.top + fi.ascent;
  1614.     FW_PlatformCoordinate drawPosX = box.left;
  1615.     
  1616.     FW_Boolean bIsStrikeOut = (font->GetFontStyle() & FW_kStrikeOut) != 0;
  1617. #endif
  1618.  
  1619.     // ----- Check vertical jusitficaiton
  1620.     switch (opt & FW_kPrivTextBoxVertJusificationMask)
  1621.     {
  1622.     case FW_kTextBoxJustifyVCenter:
  1623. #ifdef FW_BUILD_WIN
  1624.         drawPosY = (box.top + box.bottom - fontHeight) / 2;
  1625. #endif
  1626. #ifdef FW_BUILD_MAC
  1627.         drawPosY = (box.top + box.bottom + fi.ascent - fi.descent) / 2;
  1628. #endif
  1629.         break;
  1630.         
  1631.     case FW_kTextBoxJustifyBottom:
  1632.         drawPosY = box.bottom - fontHeight;
  1633.         break;
  1634.     }
  1635.  
  1636.     // ----- Draw string segments one by one
  1637.     FW_Boolean wordWrap = (opt & FW_kTextBoxWordWrap) != 0;
  1638.     FW_Boolean wordBreak = (opt & FW_kTextBoxWordBreak) != 0;
  1639.     FW_Boolean reachedBottom = FALSE;
  1640.     while (TRUE)
  1641.     {
  1642.         const char* line;
  1643.         FW_ByteCount lineLength;
  1644.         textBuffer->GetCurrentLine(line, lineLength);
  1645.         
  1646.         // ----- Draw the current segment
  1647.         FW_Boolean bCalledBefore = FALSE;
  1648.         while (!reachedBottom && FW_PrivGetStringSegment(*device, bCalledBefore,
  1649.             line, lineLength, segStart, segLen, maxWidth, actualWidth, wordWrap, wordBreak))
  1650.         {
  1651.             // ----- Check horizontal jusitficaiton
  1652.             switch (opt & FW_kPrivTextBoxHorzJusificationMask)
  1653.             {
  1654.             case FW_kTextAlignHCenter:
  1655.                 drawPosX = (box.left + box.right - actualWidth) / 2;
  1656.                 break;
  1657.             
  1658.             case FW_kTextAlignRight:
  1659.                 drawPosX = box.right - actualWidth;
  1660.                 break;
  1661.             }
  1662.  
  1663.             if (draw)
  1664.             {
  1665.                 // ----- Draw the next line -----
  1666. #ifdef FW_BUILD_WIN
  1667.                 ::TextOut(hDC, drawPosX, drawPosY, line + segStart, segLen);
  1668. #endif
  1669. #ifdef FW_BUILD_MAC
  1670.                 ::MoveTo(drawPosX, drawPosY);
  1671.                 ::DrawText((Ptr)line, segStart, segLen);
  1672.     
  1673.                 // ----- StrikeOut if necessary -----
  1674.                 if (bIsStrikeOut)
  1675.                     MacStrikeOut(device, drawPosX, drawPosY);
  1676. #endif
  1677.             }
  1678.             
  1679.             drawPosY += fontHeight;        // Move one line down
  1680.             line += segLen + segStart;    // move on to the next segment
  1681.             lineLength -= segLen + segStart;
  1682.             
  1683.             // see if we've gotten to the bottom of the rectangle and need not to continue
  1684.             reachedBottom = bClip && (drawPosY > box.bottom);
  1685.         }
  1686.         
  1687.         if (textBuffer->IsDone())
  1688.             break;
  1689.             
  1690.         if (reachedBottom)
  1691.             break;
  1692.     
  1693.         textBuffer->Advance();
  1694.     }
  1695.  
  1696.     // ----- Restore clipping region
  1697. #ifdef FW_BUILD_WIN
  1698.     if (savedDC != 0)
  1699.         ::RestoreDC(hDC, savedDC);
  1700. #endif
  1701. #ifdef FW_BUILD_MAC
  1702.     if (oldClipRgn != NULL)
  1703.     {
  1704.         ::SetClip(oldClipRgn);
  1705.         ::FW_DisposeRegion(oldClipRgn);
  1706.     }
  1707.     
  1708. #endif
  1709.  
  1710.     // ----- Return the result ----
  1711. #ifdef FW_BUILD_WIN
  1712.     return drawPosY;
  1713. #endif
  1714. #ifdef FW_BUILD_MAC
  1715.     return drawPosY - fi.ascent;
  1716. #endif
  1717. }
  1718.  
  1719. #ifdef FW_BUILD_MAC
  1720.  
  1721. //========================================================================================
  1722. // Macintosh-specific implementation
  1723. //========================================================================================
  1724.  
  1725. FW_DEFINE_AUTO(FW_PrivSelectHairline)
  1726.  
  1727. FW_PrivSelectHairline::FW_PrivSelectHairline(FW_Boolean setHairline)
  1728. :    fData(NULL)
  1729. {
  1730.     if(setHairline)
  1731.     {        
  1732.         // this memory allocation is unlikely to fail,
  1733.         // and if it does it would result in a line being drawn too fat,
  1734.         // so on failure we just refrain from setting the width
  1735.         fData = FW_PrivMemoryManager_AllocateSystemHandle(sizeof(Point));
  1736.         if(fData != nil)
  1737.         {
  1738.             const short kScaleNumerator = 1;
  1739.             const short kScaleDenominator = 28; // can be from 1 thru 128
  1740.  
  1741.             Point tempData = { kScaleNumerator, kScaleDenominator };
  1742.             **(Point**)fData = tempData;
  1743.             
  1744.             ::PicComment(eSetLineWidthPicComment, sizeof(Point), fData);
  1745.         }
  1746.     }
  1747.     
  1748.     FW_END_CONSTRUCTOR
  1749. }
  1750.  
  1751. FW_PrivSelectHairline::~FW_PrivSelectHairline()
  1752. {
  1753.     FW_START_DESTRUCTOR
  1754.     
  1755.     if(fData != NULL)
  1756.     {
  1757.         // this is done in two passes for stylewriter and laserwriter.
  1758.  
  1759.         {
  1760.             // nothing here will move memory while we have this dereferenced
  1761.             // it still contains the ratio that was set in the ctor
  1762.             Point *pData = *(Point**)fData;
  1763.             Point tempData = *pData;
  1764.             
  1765.             // 1. invert the numerator and denominator to un-scale the pen
  1766.             pData->h = tempData.v;
  1767.             pData->v = tempData.h;
  1768.         }
  1769.         
  1770.         // this inverts the scale -- for the stylewriter
  1771.         ::PicComment(eSetLineWidthPicComment, 4, fData);
  1772.         
  1773.         **(long**)fData = 0x00010001; // set the handle data to {1,1}
  1774.  
  1775.         // this is explicitly 1, 1 for the laserwriter
  1776.         ::PicComment(eSetLineWidthPicComment, 4, fData);
  1777.         
  1778.         FW_PrivMemoryManager_FreeSystemHandle(fData);
  1779.     }
  1780. }
  1781.  
  1782. //----------------------------------------------------------------------------------------
  1783. //    MacSelectInkAndStyle
  1784. //----------------------------------------------------------------------------------------
  1785.  
  1786. static void MacSelectInkAndStyle(
  1787.                         FW_CPrivGraphicsDevice* device,
  1788.                         FW_EPrivShapeCategories shapeCategory,
  1789.                         FW_ERenderVerbs renderVerb,
  1790.                         FW_HInk ink,
  1791.                         FW_HStyle style,
  1792.                         FW_Boolean& styleIsDash,
  1793.                         FW_Boolean& styleIsHairline)
  1794. {
  1795.     device->SelectInk(ink, shapeCategory, renderVerb);
  1796.     device->SelectStyle(style, ink->GetTransferMode(), styleIsDash, styleIsHairline);
  1797.     device->SetInGrafPort();
  1798. }
  1799.  
  1800. //----------------------------------------------------------------------------------------
  1801. //    MacCalcTextPosition
  1802. //----------------------------------------------------------------------------------------
  1803.  
  1804. static FW_CPlatformPoint MacCalcTextPosition(
  1805.                             FW_CPrivGraphicsDevice* device,
  1806.                             short byteCount, const char* text,
  1807.                             FW_TextAlignment textAlignment,
  1808.                             const FW_CPlatformPoint& position)
  1809. {
  1810. #ifndef FW_DEBUG
  1811.     FW_UNUSED(device);
  1812. #endif
  1813.  
  1814.     FW_ASSERT(device->GetPlatformCanvas() == FW_QDGlobals.thePort);
  1815.  
  1816.     FW_ASSERT(text != NULL);
  1817.  
  1818.     FW_CPlatformPoint plfmPos(position);
  1819.  
  1820.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseCurrentPos)
  1821.     {
  1822.         ::GetPen(&plfmPos);
  1823.     }
  1824.     else
  1825.     {
  1826.         // ----- Adjust Horizontal position
  1827.         FW_TextAlignment hAlign = textAlignment & FW_kPrivTextAlignHorzAlignMask;
  1828.         if (hAlign != FW_kTextAlignLeft)
  1829.         {
  1830.             short textWidth = ::TextWidth(text, 0, byteCount);
  1831.             if (hAlign == FW_kTextAlignRight)
  1832.                 plfmPos.h -= textWidth;
  1833.             else
  1834.                 plfmPos.h -= (textWidth / 2);
  1835.         }
  1836.     }
  1837.     
  1838.     // ----- In both cases we need to adjust the vertical position
  1839.     FW_TextAlignment vAlign = textAlignment & FW_kPrivTextAlignVertAlignMask;
  1840.     if (vAlign != FW_kTextAlignBaseLine)
  1841.     {
  1842.         FontInfo fi;
  1843.         ::GetFontInfo(&fi);
  1844.         switch (vAlign)
  1845.         {
  1846.             case FW_kTextAlignTop:
  1847.                 plfmPos.v += fi.ascent;
  1848.                 break;
  1849.                 
  1850.             case FW_kTextAlignBottom:
  1851.                 plfmPos.v -= fi.descent;
  1852.                 break;
  1853.                 
  1854.             case FW_kTextAlignVCenter:
  1855.                 plfmPos.v += fi.ascent - ((fi.descent + fi.ascent) / 2);
  1856.                 break;
  1857.         }
  1858.     }
  1859.  
  1860.     return plfmPos;
  1861. }
  1862.  
  1863. //----------------------------------------------------------------------------------------
  1864. //    MacStrikeOut
  1865. //----------------------------------------------------------------------------------------
  1866.  
  1867. static void MacStrikeOut(
  1868.         FW_CPrivGraphicsDevice* device,
  1869.         short beforePosX, short beforePosY)
  1870. {
  1871.     // ----- Get the pen position before drawing -----
  1872.     FW_CPlatformPoint afterPoint;
  1873.     ::GetPen(&afterPoint);
  1874.  
  1875.     FontInfo fi;
  1876.     ::GetFontInfo(&fi);
  1877.     
  1878.     short strikeHeight = (fi.ascent * 2) / 5;
  1879.     
  1880.     device->SetPenSize(1,1);
  1881.     device->SetInGrafPort();
  1882.     
  1883.     ::MoveTo(beforePosX, beforePosY - strikeHeight);
  1884.     ::Line(afterPoint.h - beforePosX - 1, 0);
  1885.     
  1886.     // ----- Restore the pen position -----
  1887.     ::MoveTo(afterPoint.h, afterPoint.v);
  1888. }
  1889.  
  1890. #endif
  1891.  
  1892.